using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using TTXNA.src.Util;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using TTXNA.src.Engine.Input;

namespace TTXNA.src.Engine.Controls
{
    public abstract class Control
    {
        public enum ControlState { Normal, Over, Down, Disabled }
        public enum TextAlign { Left, Right, Top, Bottom, Center }

        protected int _id;

        protected Rectangle _hotspot;
        protected ControlState _controlState;
        protected TextAlign _textAlign;
        protected RectangleF _textRect;

        protected Texture2D textureUp;

        protected RectangleF _size;
        
        protected bool _disabled;
        protected bool _hasFocus;
        protected bool _mouseDown;
        protected bool _enteredUp;

        protected int _zDepth;
        protected string _text = String.Empty;

        protected object _data;
        protected object _tag;

        protected bool _hasTouchDownPoint;
        protected Point _touchDownPoint;

        protected Matrix spriteTransform;
        protected Vector2 _position;
        protected Vector3 _renderPosition;
        protected Vector3 _center;
        //protected System.Drawing.Font systemFont;
        //protected Microsoft.DirectX.Direct3D.Font _font;

        //protected Mesh font3D;

        protected bool isMultiLine;
        protected float _fontSize;
        protected string _fontName;
        protected Color _fontColorDeselected;
        protected Color _fontColor;
        protected Color _fontColorSelected;
        //protected DrawTextFormat textFormat = DrawTextFormat.Center | DrawTextFormat.VerticalCenter;
        private int _panelID;

        private float widthScale, heightScale;

        public event ControlDelegate OnControl;
        public delegate void ControlDelegate(object data, object tag);

        public Control()
        {
            _panelID = 0;
            _controlState = ControlState.Normal;
            _textRect = new RectangleF();
            _disabled = false;
            _hasFocus = false;
            _hasTouchDownPoint = false;
            _mouseDown = false;
            _enteredUp = false;
        }

        public virtual bool KeyboardHandler(List<Keys> pressedKeys, char pressedChar, int pressedKey)
        {
            if (OnKeyDown(pressedKeys, pressedChar, pressedKey))
            {
                if (OnControl != null)
                {
                    //OnControl(_id, Data);
                    return true;
                }
                return true;
            }
            return false;
        }

        protected void DoControl()
        {
            if(OnControl != null)
            OnControl(Data, Tag);
        }

        public virtual bool MouseHandler(MouseData data)
        {
            if (_controlState != ControlState.Disabled)
            {

                // If control hadn't been clicked on, but is now, then set the touchDownPoint, and say it has one.
                if (!_hasTouchDownPoint && data.LeftMouseButtonDown)
                {
                    _touchDownPoint = data.CursorLocation;
                    _hasTouchDownPoint = true;
                }
                //If it already has a TDP, but now the mouse button has been lifted somewhere, it no longer has a TDP.
                else if (_hasTouchDownPoint && !data.LeftMouseButtonDown)
                {
                    _hasTouchDownPoint = false;
                }

                if (Contains(data.CursorLocation))   // If the mouse cursor is within the bounds of the control...
                {

                    if (data.ScrollWheelDelta != 0)   // If the mouse wheel has been scrolled.
                    {
                        OnZDelta(data);   //Let the control handle the mouse wheel scroll.
                    }

                    if (!data.LeftMouseButtonDown)    // If the LMB has been released ...
                    {
                        _enteredUp = true; // Mouse entered control bounds while it was up.

                        if (_mouseDown && _hasFocus) // and last time we looked it was down, then it must have been a click.
                        {
                            _mouseDown = false;     // Well, the mouse isn't down any more as we established.
                            _hasFocus = true;       // This control also now has focus.

                            OnMouseRelease(data); //Handle what happens when you release the mouse button on a control.

                            if (OnControl != null)  // If the event isn't null, then...
                            {
                                OnControl(Data, Tag);   //Do what needs to be done.
                            }
                        }

                        bool result = false;

                        if (State == ControlState.Over)
                        {
                            result = false;
                        }

                        State = ControlState.Over;
                        OnMouseOver(data);
                        return result;

                    }
                    else if (data.LeftMouseButtonDown && _hasTouchDownPoint)
                    {
                        if (!_mouseDown || _hasFocus)
                        {
                            State = ControlState.Down;

                            _mouseDown = true;
                            _hasFocus = true;

                            OnMouseDown(data);

                            return true;
                        }
                        else
                        {
                            _mouseDown = true;
                            return false;
                        }
                    }
                }
                else if (!Contains(data.CursorLocation))
                {
                    if (data.LeftMouseButtonDown)
                    {
                        _mouseDown = true;
                        //_enteredUp = false;

                        if (_hasFocus)
                            OnMouseDown(data);
                    }

                    //if (!buttons[0] && !(this is EditBox))
                    if (!data.LeftMouseButtonDown)
                    {
                        _enteredUp = true;
                        _hasFocus = false;
                        _mouseDown = false;
                        OnMouseRelease(data);
                    }

                    if (!_hasFocus)
                    {
                        State = ControlState.Normal;
                        return true;
                    }

                }
            }

            return false;

        }

        public virtual bool Contains(Point cursor)
        {
            return _size.Contains(cursor);
        }

        public virtual bool OnKeyDown(List<Keys> pressedKeys, char pressedChar, int pressedKey)
        {
            return false;
        }

        protected virtual void OnZDelta(MouseData data)
        {
            // Empty
        }

        protected virtual void OnMouseRelease(MouseData data) 
        { 
            // Empty
        }

        protected virtual void OnMouseDown(MouseData data)
        {
            // Empty 

        }

        protected virtual void OnMouseOver(MouseData data)
        {

        }

        public virtual void Dispose()
        {
            //if(_sprite != null) _sprite.Dispose();
            //if(_font != null) _font.Dispose();            
        }

        public virtual void OnSelected()
        {
            
            if (OnControl != null)
            {
                OnControl(Data, Tag);
            }
        }

        public virtual void OnDeselected()
        {
            if (OnControl != null)
            {
                OnControl(Data, Tag);
            }
        }

        public virtual void Render(Vector2 location)
        {
            
        }

        protected float WidthScale
        {
            get { return widthScale; }
        }

        protected float HeightScale
        {
            get { return heightScale; }
        }

        public virtual void SetSize(float newWidth, float newHeight)
        {
            _size.Width = newWidth;
            _size.Height = newHeight;

            _size.X = _position.X;
            _size.Y = _position.Y;

            if (textureUp != null)
            {

                widthScale = newWidth / (float)textureUp.Width;
                heightScale = newHeight / (float)textureUp.Height;

                _renderPosition.X = _position.X;
                _renderPosition.Y = _position.Y;

                _renderPosition.X = (_renderPosition.X * (1 / widthScale));
                _renderPosition.Y = (_renderPosition.Y * (1 / heightScale));

                _textRect.X = _position.X;
                _textRect.Y = _position.Y;
                _textRect.Width = newWidth;
                _textRect.Height = newHeight;

                //if (_font != null) _font.Dispose();

                //System.Drawing.Font systemFont = new System.Drawing.Font(_fontName, _fontSize);
                //_font = new Microsoft.DirectX.Direct3D.Font(Game.device, systemFont);

                spriteTransform = Matrix.CreateScale(widthScale, heightScale, 1f);
            }
        }

        public void SetSelectedFontColour(Color color)
        {
            _fontColorSelected = color;
        }

        //public void SetDrawTextFormats(DrawTextFormat format)
        //{
        //    textFormat = format;
        //}

        public virtual void ResizeBy(float widthFactor, float heightFactor)
        {
            float newWidth = _size.Width * widthFactor;
            float newHeight = _size.Height * heightFactor;

            _fontSize = _fontSize * heightFactor;

            SetSize(newWidth, newHeight);

            float newLeft = _size.X * widthFactor;
            float newTop = _size.Y * heightFactor;

            Position = new Vector2(newLeft, newTop);
        }

        public virtual object Data
        {
            get { return _data; }
            set { _data = value; }
        }

        public virtual object Tag
        {
            get { return _tag; }
            set { _tag = value; }
        }

        public virtual bool Disabled
        {
            get { return (_controlState == ControlState.Disabled); }
            set
            {
                if (value)
                {
                    _controlState = ControlState.Disabled;

                }
                else
                {
                    _controlState = ControlState.Normal;

                }
            }
        }

        public virtual Color FontColor
        {
            get { return _fontColor; }
            set { _fontColor = value; }
        }

        public virtual bool HasFocus
        {
            get { return _hasFocus; }
            set { _hasFocus = value; }

        }

        public virtual int ID
        {
            get { return _id; }
        }

        public virtual bool MultiLine
        {
            get { return isMultiLine; }
            set { isMultiLine = value; }
        }

        public virtual int PanelID
        {
            get { return _panelID; }
            set { _panelID = value; }
        }

        public virtual Vector2 Position
        {
            get { return _position; }
            set { 
                _position = value;
                SetSize(_size.X, _size.Y);
            }
        }

        public virtual RectangleF Area
        {
            get { return _size; }
        }

        public virtual Vector2 Size
        {
            get { return _size.Size; }
        }

        public virtual ControlState State
        {
            get { return _controlState; }
            set { 
                _controlState = value; 
            }


        }

        public virtual string Text
        {
            get { return _text; }
            set { _text = value; }
        }

        public virtual int ZDepth
        {
            get { return _zDepth; }
            set { _zDepth = value; }
        }

    }
}
